package lumis.content.hyperlink;

import java.io.IOException;
import java.util.Arrays;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.PageContext;

import lumis.content.ContentManagerFactory;
import lumis.content.core.Content;
import lumis.content.search.common.IContentIndexer;
import lumis.doui.search.common.IDouiIndexer;
import lumis.doui.source.ISourceContext;
import lumis.doui.source.SourceContext;
import lumis.doui.source.SourceFactory;
import lumis.doui.source.TabularSource;
import lumis.portal.PageNotFoundException;
import lumis.portal.PortalContext;
import lumis.portal.PortalException;
import lumis.portal.PortalObjectNotFoundException;
import lumis.portal.PortalRequestParameters;
import lumis.portal.UnexpectedException;
import lumis.portal.controller.ControllerException;
import lumis.portal.controller.ControllerHtml;
import lumis.portal.manager.ManagerFactory;
import lumis.portal.page.PageConfig;
import lumis.portal.serviceinstance.ServiceInstanceConfig;
import lumis.portal.transaction.PortalTransactionFactory;
import lumis.search.SearchAttributes;
import lumis.search.SearchHit;
import lumis.search.SearchQuery;
import lumis.search.SearchResults;
import lumis.search.Searcher;
import lumis.search.SearcherFactory;
import lumis.search.filter.SearchClause;
import lumis.search.filter.SearchFilterGroup;
import lumis.util.CookieUtil;
import lumis.util.ITransaction;
import lumis.util.LocaleUtil;

/**
 *	Get from the Search framework the URL for the provided contentId.
 *	@version $Revision: 11096 $ $Date: 2009-11-19 17:12:05 -0200 (Thu, 19 Nov 2009) $ 
 *	@since 4.2.0
 */
public class ContentHyperLinkControllerHtml extends ControllerHtml
{
	public ContentHyperLinkControllerHtml(HttpServletRequest request, HttpServletResponse response, PageContext pageContext) throws ControllerException, PortalException
	{
		super(request, response);
	}

	public void hyperLink() throws ControllerException, PortalException
	{
		ITransaction transaction = PortalTransactionFactory.createTransaction();
		try
		{
			transaction.begin();
			
			String url = null;
			String contentId = request.getParameter(PortalRequestParameters.PAGE_PARAMETER_ITEM_ID);
			if (contentId != null)
			{
				Content content = ContentManagerFactory.getContentManager().getContent(contentId);
				
				ServiceInstanceConfig serviceInstanceConfig = ManagerFactory.getServiceInstanceManager().get(content.getServiceInstanceId(), transaction);
				ISourceContext sourceContext = new SourceContext(sessionConfig, serviceInstanceConfig, transaction);
				TabularSource source = (TabularSource)SourceFactory.createSource(content.getSourceId(), sourceContext);
				if (source.isSearchEnabled())
				{
					String localeParam = request.getParameter("locale");
					if (localeParam == null || localeParam.length() == 0)
						localeParam = sessionConfig.getLocale().toString();
					
					Searcher searcher = SearcherFactory.getSearcher(source.getSearcherEngineId(), source.getSearcherId());
					SearchHit hit = search(searcher, content, localeParam);
					if (hit == null)
					{
						hit = search(searcher, content, IDouiIndexer.FIELDNAME_LANGUAGE_ALL_VALUE);
					}
					else
					{
						Locale curLocale = LocaleUtil.FromString(localeParam);
						sessionConfig.setLocale(curLocale);
						CookieUtil.setCookie(request, response, "lumUserLocale", curLocale.toString());
					}
					
					if (hit != null)
						url = hit.getUrl();
				}				
			}
			if (url != null)
			{
				response.sendRedirect(url);
			}
			else
			{
				throw new PageNotFoundException();
			}
			transaction.commit();
		}
		catch (PortalObjectNotFoundException e) 
		{
			throw new PageNotFoundException(e);
		}
		catch (IOException e) 
		{
			throw new UnexpectedException(e);
		}
		finally
		{
			transaction.dispose();
		}
	}
	
	/**
	 * Searches for a content in a specific locale.
	 * @param searcher the searcher to be used.
	 * @param content the content.
	 * @param locale the locale. May be {@link IDouiIndexer#FIELDNAME_LANGUAGE_ALL_VALUE}
	 * for indicating all locales.
	 * @return the first search hit that has no <code>parentId</code>, or <code>null</code> if it was not found.
	 * @throws PortalException
	 * @since 4.2.0
	 */
	private SearchHit search(Searcher searcher, Content content, String locale) throws PortalException
	{
		SearchQuery searchQuery = getSearchQuery(content, locale);
		
		SearchResults searchResults = searcher.search(searchQuery);
		for(int i=0; i<searchResults.getHitCount(); i++)
		{
			if(searchResults.getHit(i).getParentId() == null)
				return  searchResults.getHit(i);
		}
		
		return null;
	}
	
	/**
	 * Creates a search query to search for a content in a locale.
	 * @param content the content.
	 * @param locale the locale.  May be {@link IDouiIndexer#FIELDNAME_LANGUAGE_ALL_VALUE}
	 * for indicating all locales.
	 * @return the query.
	 * @since 4.2.0
	 */
	private SearchQuery getSearchQuery(Content content, String locale)
	{
		SearchQuery searchQuery = new SearchQuery();
		
		SearchFilterGroup controlFilter = new SearchFilterGroup();
		SearchClause serviceInstanceClause = new SearchClause();
		serviceInstanceClause.setScope(IDouiIndexer.FIELDNAME_SERVICEINSTANCEID);
		serviceInstanceClause.setTerms(content.getServiceInstanceId());
		
		SearchClause contentClause = new SearchClause();
		contentClause.setScope(IContentIndexer.FIELDNAME_CONTENT_ID);
		contentClause.setTerms(content.getId());
		
		SearchClause languageClause = new SearchClause();
		languageClause.setScope(IDouiIndexer.FIELDNAME_LANGUAGE);
		languageClause.setTerms(locale.toUpperCase());
		
		controlFilter.setFilters(Arrays.asList(serviceInstanceClause, contentClause, languageClause));
		
		searchQuery.setControlFilter(controlFilter);

		// add search control info
		SearchAttributes searchAttributes = searchQuery.getAttributes();
		searchAttributes.addAttributeValue(IDouiIndexer.FIELDNAME_PORTALDATAPATH, PortalContext.getDataPath(""));
		searchAttributes.addAttributeValue(IDouiIndexer.FIELDNAME_SERVICEINSTANCEID, content.getServiceInstanceId());

		return searchQuery;
	}
	
}
